﻿package Daos;

import java.sql.Connection;
import java.sql.Date;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import logica.jugadores.Jugador;
import logica.objetos.Objeto;
import logica.objetos.Partida;
import enums.TipoEstado;
import enums.TipoObjeto;
import excepciones.PersistenciaException;

/**
 * 
 * @author GRUPODOS
 * @version clase que maneja la persistencia de las partidas
 * 
 */
public class PartidasActivas {
    /**
     * ingresa una partida nueva
     * 
     * @param nombre
     *            el nombre de la partida. Si viene vacio, sera el id generado
     * @return el numero de identificacion de la partida
     * @throws PerssistenciaException
     *             si ocurre error SQL
     */
    public Partida iniciarPartida(Connection con, String nombre, int idMapa, int cargueroEnTurno)
	    throws PersistenciaException {
	Partida resu = null;
	try {
	    ConsultasSQL consultas = new ConsultasSQL();
	    String query = consultas.ingresarPartida();
	    PreparedStatement ps = con.prepareStatement(query, Statement.RETURN_GENERATED_KEYS);
	    ps.setInt(1, 0);
	    ps.setInt(2, idMapa);
	    ps.setString(3, nombre);
	    ps.setInt(4, TipoEstado.ESPERANDO.getValue());
	    ps.setInt(5, 4);// numero puesto para la prueba, despues se levanta
			    // desde configuracion
	    Calendar fecha = Calendar.getInstance();
	    ps.setDate(6, new java.sql.Date(fecha.getTime().getTime()));
	    ps.setString(7, null);
	    ps.setString(8, null);
	    ps.setInt(9, 0);
	    ps.setInt(10, cargueroEnTurno);
	    ps.executeUpdate();
	    ResultSet rs = ps.getGeneratedKeys();
	    if (rs.next())
		resu = buscarPartidaPorId(con, rs.getInt(1));
	    // falta el control de si el nombre viene vacio, que quede con el id
	    // de la partida,
	    // pero no s ehizo porque no existe todavia el metodo modificar de
	    // partidas
	    rs.close();
	    ps.close();

	} catch (SQLException e) {
	    throw new PersistenciaException(e.getMessage());
	} catch (PersistenciaException e) {
	    throw new PersistenciaException(e.getMensaje());
	}
	return resu;
    }

    /**
     * busca una partida a la que esta vinculado el jugador cuyo id se ingresa
     * 
     * @param idJugador
     * @return el id de la partida
     * @throws PersistenciaException
     *             si ocurre error SQL
     */
    public int buscarIdPartidaPorJugador(Connection t, String idJugador)
	    throws PersistenciaException {
	int resu = 0;
	try {
	    ConsultasSQL consultas = new ConsultasSQL();
	    String consulta = consultas.buscarIdPartidaPorIdJugador();
	    PreparedStatement ps = t.prepareStatement(consulta);
	    ps.setString(1, idJugador);
	    ps.setString(2, idJugador);
	    ResultSet rs = ps.executeQuery();
	    if (rs.next())
		resu = rs.getInt(1);
	    rs.close();
	    ps.close();
	} catch (SQLException e) {
	    throw new PersistenciaException(e.getMessage());
	} 
	return resu;
    }

    /**
     * dado el id de un jugador, busca la partida a la que esta asociado
     * 
     * @param idJugador
     *            es el id del jugador
     * @return la partida a la que esta vinculado, si es ninguna retorna null
     * @throws PersistenciaException
     *             si ocurre error SQL
     */
    public Partida buscarPartidaPorJugador(Connection t, String idJugador)
	    throws PersistenciaException {
	Partida resu = null;
	try {
	    ConsultasSQL consultas = new ConsultasSQL();
	    String consulta = consultas.buscarPartidaPorJugador();
	    PreparedStatement ps = t.prepareStatement(consulta);
	    ps.setString(1, idJugador);
	    ps.setString(2, idJugador);
	    ResultSet rs = ps.executeQuery();
	    if (rs.next()) {
		int identificador = rs.getInt(1);
		int idMapa = rs.getInt(2);
		String nombre = rs.getString(3);
		int estadoInt = rs.getInt(4);		

		int movPorTurno = rs.getInt(5);
		Date fechasql = rs.getDate(6);
		Calendar fecha = Calendar.getInstance();
		fecha.setTimeInMillis(fechasql.getTime());
		// los jugadores
		String idJug1 = rs.getString(7);
		String idJug2 = rs.getString(8);
		
		int numeroTurno = rs.getInt(9);
		int cargueroEnTurno = rs.getInt(10);
		
		Jugadores jug = new Jugadores();
		Jugador j1 = null, j2 = null;
		if (idJug1 != null)
		    j1 = jug.buscarJugadorPorId(t, idJug1);
		if (idJug2 != null)
		    j2 = jug.buscarJugadorPorId(t, idJug2);

		String cualTurno = null;
		if (j1 != null && j1.isTieneTurno())
		    cualTurno = idJug1;
		else if (j2 != null && j2.isTieneTurno())
		    cualTurno = idJug2;
		// los objetos
		Objetos objetos = new Objetos();
		Objeto[] colObjetos = objetos.buscarTodosLosObjetosDePartida(t,
			identificador);
		
		resu = new Partida(identificador, fecha, j1, j2, colObjetos, TipoEstado.from(estadoInt),
			fecha, cualTurno, nombre, idMapa, numeroTurno, cargueroEnTurno);
	    }

	    rs.close();
	    ps.close();
	} catch (SQLException e) {
	    throw new PersistenciaException(e.getMessage());
	} catch (PersistenciaException e) {
	    throw new PersistenciaException(e.getMensaje());
	}
	return resu;
    }

    /**
     * dado el id de una partida, retorna los datos completos de la misma
     * 
     * @param idPartida
     *            el id de la partida buscada
     * @return la aprtida con ese id
     * @throws PersistenciaException
     *             si ocurre error SQL
     */
    public Partida buscarPartidaPorId(Connection t, int idPartida)
	    throws PersistenciaException {
	Partida resu = null;
	try {
	    ConsultasSQL consultas = new ConsultasSQL();
	    String consulta = consultas.buscarPartidaPorId();
	    PreparedStatement ps = t.prepareStatement(consulta);
	    try {
		int idPartidaInt = idPartida;
		ps.setInt(1, idPartidaInt);
		ResultSet rs = ps.executeQuery();
		if (rs.next()) {
		    int identificador = rs.getInt(1);
		    int idMapa = rs.getInt(2);
		    String nombre = rs.getString(3);		   
		    int estadoInt = rs.getInt(4);		   
		    int movPorTurno = rs.getInt(5);
		    Date fechasql = rs.getDate(6);
		    Calendar fecha = Calendar.getInstance();
		    fecha.setTimeInMillis(fechasql.getTime());
		    // los jugadores
		    Jugadores jug = new Jugadores();
		    String idJug1 = rs.getString(7);
		    String idJug2 = rs.getString(8);
		    
		    int numeroTurno = rs.getInt(9);
			int cargueroEnTurno = rs.getInt(10);

		    Jugador j1 = null, j2 = null;
		    if (idJug1 != null)
			j1 = jug.buscarJugadorPorId(t, idJug1);
		    if (idJug2 != null)
			j2 = jug.buscarJugadorPorId(t, idJug2);

		    String cualTurno = null;
		    if (j1 != null && j1.isTieneTurno())
			cualTurno = idJug1;
		    else if (j2 != null && j2.isTieneTurno())
			cualTurno = idJug2;

		    // los objetos
		    Objetos objetos = new Objetos();
		    // Objeto[]colObjetos = new Objeto[0];
		    Objeto[] colObjetos = objetos
			    .buscarTodosLosObjetosDePartida(t, identificador);
		
		    resu = new Partida(identificador, fecha, j1, j2, colObjetos,
			    TipoEstado.from(estadoInt), fecha, cualTurno, nombre, idMapa, numeroTurno, cargueroEnTurno);
		}
		rs.close();
		ps.close();

	    } catch (NumberFormatException ex) {
		throw new PersistenciaException(ex.getMessage());
	    }
	} catch (SQLException e) {
	    throw new PersistenciaException(e.getMessage());
	} catch (PersistenciaException e) {
	    throw new PersistenciaException(e.getMensaje());
	}
	return resu;
    }

    /**
     * busca una partida por su id si tiene el jugador 2 en null
     * 
     * @param t
     *            la transaccion
     * @param idPartida
     *            el String con el id de la partida buscada
     * @return la partida si es que no tienen jugador 2
     * @throws PersistenciaException
     *             si ocurre sql exception
     */
    public Partida buscarPartidaSinJugador2(Connection t, String idPartida)
	    throws PersistenciaException {
	Partida resu = null;
	ConsultasSQL consultas = new ConsultasSQL();
	String sql = consultas.listarPartidasSinJugador2();
	try {
	    PreparedStatement ps = t.prepareStatement(sql);
	    ps.setInt(1, Integer.parseInt(idPartida));
	    ResultSet rs = ps.executeQuery();
	    if (rs.next()) {
		int idPart = rs.getInt(1);
		resu = this.buscarPartidaPorId(t, idPart);
	    }
	} catch (SQLException e) {
	    throw new PersistenciaException(e.getMessage());
	} catch (PersistenciaException e) {
	    throw new PersistenciaException(e.getMensaje());
	}
	return resu;
    }

    // Listar partidas por estado ()
    public List<Partida> listarPartidasPorEstado(Connection t,
	    TipoEstado estado) throws PersistenciaException {
	List<Partida> resu = new ArrayList<Partida>();
	try {
	    ConsultasSQL consultas = new ConsultasSQL();
	    int estadoBase = -1;	   
		estadoBase = estado.getValue();
	    String consulta = consultas.listPartidaPorEstado();
	    PreparedStatement pstmt = t.prepareStatement(consulta);
	    pstmt.setInt(1, estadoBase);
	    ResultSet rs = pstmt.executeQuery();
	    while (rs.next()) {
		int idPart = rs.getInt("idPartidas");
		Partida p = this.buscarPartidaPorId(t,idPart);
		resu.add(p);
	    }
	    rs.close();
	    pstmt.close();
	} catch (SQLException e) {
	    throw new PersistenciaException(e.getMessage());
	} catch (PersistenciaException e) {
	    throw new PersistenciaException(e.getMensaje());
	}
	return resu;
    }

    public void ingresarJugadorEnPartida(Connection t, int idPartida,
	    String resu) throws PersistenciaException {	
	try {
	    ConsultasSQL consultas = new ConsultasSQL();
	    String sql = "";
	    Jugador[] p = this.buscarJugadoresDePartidaPorIdPartida(t,
		    (idPartida + ""));
	    Jugador j1 = p[0];
	    Jugador j2 = p[1];
	    if (j1 == null) {
		sql = consultas.ingresarPrimerJugadorEnPartida();
	    } else if (j2 == null) {
		sql = consultas.ingresarSegundoJugadorEnPartida();
	    } else {
		throw new PersistenciaException(
			"La partida no tiene jugadores libres.");
	    }
	    PreparedStatement ps = t.prepareStatement(sql);
	    ps.setString(1, resu + "");
	    ps.setInt(2, idPartida);
	    int n = ps.executeUpdate();
	    if (n == 0)
		throw new PersistenciaException(
			"error al vincular al jugador a la partida");

	    ps.close();
	} catch (SQLException e) {
	    throw new PersistenciaException(e.getMessage());
	} catch (PersistenciaException e) {
	    throw new PersistenciaException(e.getMensaje());
	}
    }

    /**
     * solo se retorna los dos jugadores de la partida
     * 
     * @param t
     * @param string
     * @return
     * @throws PersistenciaException
     */
    private Jugador[] buscarJugadoresDePartidaPorIdPartida(Connection t,
	    String idPartida) throws PersistenciaException {	
	Jugador[] resu = new Jugador[2];
	ConsultasSQL consultas = new ConsultasSQL();
	String sql = consultas.buscarJugadoresPorIdPartida();
	Jugador j1 = null, j2 = null;
	Jugadores jugadores = new Jugadores();
	try {
	    PreparedStatement ps = t.prepareStatement(sql);
	    ps.setInt(1, Integer.parseInt(idPartida));
	    ResultSet rs = ps.executeQuery();
	    if (rs.next()) {
		String id1 = rs.getString(1);
		String id2 = rs.getString(2);
		if (id1 != null) {
		    j1 = jugadores.buscarJugadorPorId(t, id1);
		}
		if (id2 != null) {
		    j2 = jugadores.buscarJugadorPorId(t, id2);
		}
	    }
	    resu[0] = j1;
	    resu[1] = j2;

	    rs.close();
	    ps.close();
	} catch (SQLException e) {
	    throw new PersistenciaException(e.getMessage());
	} catch (PersistenciaException e) {
	    throw new PersistenciaException(e.getMensaje());
	}
	return resu;
    }
    
    public void actualizarEstadoCargoJugador1(Connection t, int idPartida, boolean cargo) throws PersistenciaException{
    	ConsultasSQL consultas = new ConsultasSQL();
    	String sql = consultas.cambiarEstadoCargarJugador1();

    	try {
    	    PreparedStatement ps = t.prepareStatement(sql);	   
    	    // Seteo parametros
    	    ps.setBoolean(1, cargo);
    	    ps.setInt(2,idPartida);
    	    // Ejectuo el statement
    	    ps.executeUpdate();
    	    ps.close();

    	} catch (SQLException e) {
    	    throw new PersistenciaException(e.getMessage());
    	} 
    }
    
    public void actualizarEstadoCargoJugador2(Connection t, int idPartida, boolean cargo) throws PersistenciaException{
    	ConsultasSQL consultas = new ConsultasSQL();
    	String sql = consultas.cambiarEstadoCargarJugador2();

    	try {
    	    PreparedStatement ps = t.prepareStatement(sql);	   
    	    // Seteo parametros
    	    ps.setBoolean(1, cargo);
    	    ps.setInt(2,idPartida);
    	    // Ejectuo el statement
    	    ps.executeUpdate();
    	    ps.close();

    	} catch (SQLException e) {
    	    throw new PersistenciaException(e.getMessage());
    	} 
    }
    
    public boolean verificarJugador1Cargando(Connection t, int idPartida) throws PersistenciaException{
    	ConsultasSQL consultas = new ConsultasSQL();
    	String sql = consultas.verificarJugador1Cargando();

    	try {
    	    PreparedStatement ps = t.prepareStatement(sql);	   
    	    // Seteo parametros    	    
    	    ps.setInt(1,idPartida);
    	    // Ejectuo el statement
    	    ResultSet rs = ps.executeQuery();
    	    boolean encontro = rs.next();
    	    
    	    rs.close();
    	    ps.close();
    	    
    	    return encontro;  	    

    	} catch (SQLException e) {
    	    throw new PersistenciaException(e.getMessage());
    	} 
    }
    
    public boolean verificarJugador2Cargando(Connection t, int idPartida) throws PersistenciaException{
    	ConsultasSQL consultas = new ConsultasSQL();
    	String sql = consultas.verificarJugador2Cargando();

    	try {
    	    PreparedStatement ps = t.prepareStatement(sql);	   
    	    // Seteo parametros    	    
    	    ps.setInt(1,idPartida);
    	    // Ejectuo el statement
    	    ResultSet rs = ps.executeQuery();
    	    boolean encontro = rs.next();
    	    
    	    rs.close();
    	    ps.close();
    	    
    	    return encontro;  	    

    	} catch (SQLException e) {
    	    throw new PersistenciaException(e.getMessage());
    	} 
    }
    
    /**
     * actualiza el estado de la partida cuyo id se ingresa
     * @param t la transaccion
     * @param idPartida el identificador de la partida
     * @param estadoPartida el nuevo estado a setear
     * @throws PersistenciaException si ocurre error SQL
     */
    public void actualizarEstadoPartida(Connection t, int idPartida,
	    TipoEstado estadoPartida) throws PersistenciaException {
	ConsultasSQL consultas = new ConsultasSQL();
	String sql = consultas.actualizarEstadoPartida();

	try {
	    PreparedStatement ps = t.prepareStatement(sql);	   
	    // Seteo parametros
	    ps.setInt(1, estadoPartida.getValue());
	    ps.setInt(2,idPartida);
	    // Ejectuo el statement
	    ps.executeUpdate();
	    ps.close();

	} catch (SQLException e) {
	    throw new PersistenciaException(e.getMessage());
	} 
    }
    
    public void actualizarTurnoPartida(Connection t, int idPartida,
	    int numeroTurno) throws PersistenciaException{
    	ConsultasSQL consultas = new ConsultasSQL();
    	String sql = consultas.actualizarTurnoPartida();

    	try {
    	    PreparedStatement ps = t.prepareStatement(sql);	   
    	    // Seteo parametros
    	    ps.setInt(1, numeroTurno);
    	    ps.setInt(2,idPartida);
    	    // Ejectuo el statement
    	    ps.executeUpdate();
    	    ps.close();
    	} catch (SQLException e) {
    	    throw new PersistenciaException(e.getMessage());
    	} 
    }

    /**
     * busca el id del jugador con ese barco en esa partida <br>
     * null si no hay ninguno * 
     * @param t la transaccion
     * @param barco el tipo d ebarco
     * @return el id del jugador que tiene asignado este barco en esta partida
     * @throws PersistenciaException si ocurre error SQL
     */
    public String buscarJugadorPorBarco(Connection t, TipoObjeto barco,
	    int idPartida) throws PersistenciaException {
	
	String resu = null;
	Jugadores jugadores = new Jugadores();
	Objetos objetos = new Objetos();
	Partida partida = buscarPartidaPorId(t,idPartida);
	Objeto o = objetos.buscarBarcoEnPartida(t, partida, barco);
	if (o != null) {
	    int idObjeto = o.getIdentificador();
	    resu = jugadores.buscarJugadorPorBarco(t, idObjeto);
	}
	return resu;
    }

}